package com.fpd.exceptions;

import java.util.Map;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.xml.bind.ValidationException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;
import com.fpd.tools.Tool;
import lombok.extern.slf4j.Slf4j;

/**
 * 异常处理类
 */
@ControllerAdvice
@ResponseBody
@Slf4j
public class CommonExceptionAdvice extends CommonHandel {

	@Value("${spring.servlet.multipart.max-file-size}")
	private String maxFileSize;

	@Value("${spring.servlet.multipart.max-request-size}")
	private String maxRequestSize;

	/**
	 * 400 - Bad Request
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(MissingServletRequestParameterException.class)
	public Map<String, Object> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
		log.error("缺少请求参数", e);
		return this.error("400", "缺少请求参数：" + e.getMessage());
	}

	/**
	 * 400 - Bad Request
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(HttpMessageNotReadableException.class)
	public Map<String, Object> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
		log.error("参数解析失败", e);
		return this.error("400", "参数解析失败：" + e.getMessage());
	}

	/**
	 * 400 - Bad Request
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(MethodArgumentNotValidException.class)
	public Map<String, Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
		log.error("参数验证失败", e);
		BindingResult result = e.getBindingResult();
		FieldError error = result.getFieldError();
		String field = error.getField();
		String code = error.getDefaultMessage();
		String message = String.format("%s:%s", field, code);
		return this.error("400", "参数验证失败：" + message);
	}

	/**
	 * 400 - Bad Request
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(BindException.class)
	public Map<String, Object> handleBindException(BindException e) {
		log.error("参数绑定失败", e);
		BindingResult result = e.getBindingResult();
		FieldError error = result.getFieldError();
		String field = error.getField();
		String code = error.getDefaultMessage();
		String message = String.format("%s:%s", field, code);
		return this.error("400", "参数数据类型绑定失败：" + message);
	}

	/**
	 * 400 - Bad Request
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(ConstraintViolationException.class)
	public String handleServiceException(ConstraintViolationException e) {
		log.error("参数验证失败", e);
		Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
		ConstraintViolation<?> violation = violations.iterator().next();
		String message = violation.getMessage();
		return "参数验证失败" + message;

	}

	/**
	 * 400 - Bad Request
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(ValidationException.class)
	public String handleValidationException(ValidationException e) {
		log.error("参数验证失败", e);
		return "参数验证失败";
	}

	/**
	 * 404 - Not Found
	 */
	@ResponseStatus(HttpStatus.NOT_FOUND)
	@ExceptionHandler(NoHandlerFoundException.class)
	public Map<String, Object> noHandlerFoundException(NoHandlerFoundException e) {
		log.error("Not Found", e);
		return this.error("404", "请求URL地址不存在");
	}

	/**
	 * 405 - Method Not Allowed
	 */
	@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
	public Map<String, Object> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
		log.error("不支持当前请求方法", e);
		return this.error("405", "请求方法错误：" + e.getMethod());
	}

	/**
	 * 415 - Unsupported Media Type
	 */
	@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
	@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
	public Map<String, Object> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
		log.error("不支持当前媒体类型", e);
		return this.error("415", "不支持当前媒体类型");
	}

	/**
	 * 业务层需要自己声明异常的情况
	 */
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler(ServiceException.class)
	public String handleServiceException(ServiceException e) {
		log.error("业务逻辑异常", e);
		return "业务逻辑异常：" + e.getMessage();
	}

	/**
	 * 操作数据或库出现异常
	 */
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler(DataDoException.class)
	public Map<String, Object> handleException(DataDoException e) {
		log.error("操作数据库出现异常:", e);
		return this.error("500", "操作数据库出现异常：字段重复、有外键关联等");
	}
	/**
	 * 操作数据或库出现异常
	 */
	@ResponseStatus(HttpStatus.OK)
	@ExceptionHandler(ParameterException.class)
	public Map<String, Object> parameterException(ParameterException e) {
		log.error("参数缺失:", e);
		return this.error("004", e.getMessage());
	}
	/**
	 * 未登录
	 */
	@ResponseStatus(HttpStatus.OK)
	@ExceptionHandler(NoLoginException.class)
	public Map<String, Object> NoLoginException(NoLoginException e) {
		log.error("未登录，请先登录:");
		return this.error("1000", e.getMessage());
	}

	/**
	 * 无操作权限
	 */
	@ResponseStatus(HttpStatus.OK)
	@ExceptionHandler(NoPermissionException.class)
	public Map<String, Object> NoPermissionException(NoPermissionException e) {
		log.error("无操作权限:", e);
		return this.error("1001", e.getMessage());
	}

	/**
	 * 文件不存在
	 */
	@ResponseStatus(HttpStatus.OK)
	@ExceptionHandler(FileNotFoundException.class)
	public Map<String, Object> FileNotFoundException(FileNotFoundException e) {
		log.error("文件不存在:", e);
		return this.error("1002", e.getMessage());
	}

	/**
	 * 文件上传大小超出限制
	 */
	@ResponseStatus(HttpStatus.OK)
	@ExceptionHandler(MaxUploadSizeExceededException.class)
	public Map<String, Object> MaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
		log.error("上传文件大小超出限制:", e);
		String msg = "上传单个文件最大大小为：" + maxFileSize + "，单次上传总文件最大大小为：" + maxRequestSize;
		return this.error("1003", msg);
	}

	/**
	 * 获取其它异常。包括500
	 *
	 * @param e
	 * @return
	 * @throws Exception
	 */
	@ExceptionHandler(value = Exception.class)

	public Map<String, Object> defaultErrorHandler(Exception e) {
		log.error("Exception", e);
		String msg = Tool.isBlank(e.getMessage()) ? "系统异常，请联系管理员解决" : e.getMessage();
		return this.error("500", msg);
	}

}
